/*
 * Copyright 2017 - 2025 the original author or authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see [https://www.gnu.org/licenses/]
 */

package infra.web.accept;

import org.jspecify.annotations.Nullable;

import infra.http.HttpHeaders;
import infra.http.MediaType;
import infra.web.RequestContext;

/**
 * {@link ApiVersionResolver} that extracts the version from a media type
 * parameter found in the Accept or Content-Type headers.
 *
 * @author Rossen Stoyanchev
 * @author <a href="https://github.com/TAKETODAY">海子 Yang</a>
 * @since 5.0
 */
public class MediaTypeParamApiVersionResolver implements ApiVersionResolver {

  private final MediaType compatibleMediaType;

  private final String parameterName;

  /**
   * Create an instance.
   *
   * @param compatibleMediaType the media type to extract the parameter from with
   * the match established via {@link MediaType#isCompatibleWith(MediaType)}
   * @param paramName the name of the parameter
   */
  public MediaTypeParamApiVersionResolver(MediaType compatibleMediaType, String paramName) {
    this.compatibleMediaType = compatibleMediaType;
    this.parameterName = paramName;
  }

  @Nullable
  @Override
  public String resolveVersion(RequestContext request) {
    var headers = request.requestHeaders().getOrEmpty(HttpHeaders.ACCEPT);
    for (String header : headers) {
      for (MediaType mediaType : MediaType.parseMediaTypes(header)) {
        if (compatibleMediaType.isCompatibleWith(mediaType)) {
          return mediaType.getParameter(parameterName);
        }
      }
    }
    String header = request.getContentType();
    for (MediaType mediaType : MediaType.parseMediaTypes(header)) {
      if (compatibleMediaType.isCompatibleWith(mediaType)) {
        return mediaType.getParameter(parameterName);
      }
    }
    return null;
  }

}
